package control;

import java.util.ArrayList;
import java.util.Random;
import mappers.ClubMapper;
import mappers.EventMapper;
import mappers.MatchMapper;
import mappers.PlayerMapper;
import model.Club;
import model.Event;
import model.Match;
import model.Player;

public class SBU {

    private static SBU instance;
    private ArrayList<Match> tournamentMatches;
    private ArrayList<Player> players;
    private int matchId;

    private SBU() {
        tournamentMatches = MatchMapper.getInstance().getTable();
        players = PlayerMapper.getInstance().getPlayers();
        if (tournamentMatches.isEmpty()) {
            createMatchlist();
        }
        matchId = 1;
    }

    public static SBU getInstance() {
        if (instance == null) {
            instance = new SBU();
        }
        return instance;
    }

    public ArrayList<Player> getPlayers() {
        return players;
    }

    public ArrayList<Player> getPlayers(Match match) {
        return PlayerMapper.getInstance().getPlayers(match);
    }

    public void createMatchlist() {
        int division = 1;

        if (!tournamentMatches.isEmpty()) {
            for (int i = tournamentMatches.size() - 1; i >= 0; i--) {
                tournamentMatches.remove(i);
            }
        }
       
        // For hver division løbes klubberne igennem og hver klub får en kamp
        // på udebane og hjemmebane.
        while (division <= 3) {

            //Assign the teams with their respective matches.
            ArrayList<Match> freeMatches = generateMatches(division);

            //Bland de genererede freeMatches.
            shuffleMatches(freeMatches);

            //Giver de blandede matches en tuneringsrunde/tidspunkt.
            assignTournamentRounds(freeMatches);

            division++; 
            MatchMapper.getInstance().insertMatches(tournamentMatches);
        }
        //Indsæt kampene i databasen med insertMatches metoden.
       
    }

    public ArrayList<Match> generateMatches(int division) {
        ArrayList<Match> matches = new ArrayList<>();
        ClubMapper cm = ClubMapper.getInstance();
        //Henter klubberne for den angivne division.
        ArrayList<Club> clubs = cm.getClubs(division);
        //Løber klubberne igennem, klub 0 mod klub 1, klub 1 mod klub 2 osv.
        for (int i = 0; i < clubs.size() - 1; i++) {
            for (int j = i + 1; j < clubs.size(); j++) {
                    matches.add(new Match(matchId, clubs.get(i), clubs.get(j), clubs.get(i).getStadium(), false));
                    matchId++;
                    matches.add(new Match(matchId, clubs.get(j), clubs.get(i), clubs.get(j).getStadium(), false));
                    matchId++;
            }
        }

        return matches;
    }

    public void shuffleMatches(ArrayList<Match> freeMatches) {
        for (int i = 0; i < freeMatches.size(); i++) {
            Random ran = new Random();
            int i2 = ran.nextInt(freeMatches.size());

            //Swapper i med en tilfældig match i freeMatches.
            Match temp = freeMatches.get(i);
            freeMatches.set(i, freeMatches.get(i2));
            freeMatches.set(i2, temp);
        }
    }

    public void assignTournamentRounds(ArrayList<Match> freeMatches) {
        //Nu skal kampene tildeles en turneringsrunde (simplificeret dato).
        //Den nuværende turneringsrunde.
        int round = 1;

        //Så længe der stadig er elementer i freeMatches samlingen, skal
        //den producere tourneringsrunder.
        while (!freeMatches.isEmpty()) {
            //Der laves en ny rundeliste for hver iteration.
            ArrayList<Match> roundMatches = new ArrayList<>();
            //Her tildeles et spilletidspunkt til holdende hvis betingelserne
            //overholdes.
            for (int i = freeMatches.size() - 1; i >= 0; i--) {
                Match m1 = freeMatches.get(i);
                if (!oneTeamAlreadyPlaying(m1, roundMatches)) {
                    //Den match der får et spilletidspunkt er ikke længere
                    //ledig.
                    freeMatches.remove(i);
                    m1.setTournamentRound(round);
                    roundMatches.add(m1);
                }
            }

            // Alle kampe med tourneringsrunder tilføjes til tournamentMatches listen.
            for (int i = 0; i < roundMatches.size(); i++) {
                tournamentMatches.add(roundMatches.get(i));
            }
            round++;
        }
    }

    //Sikrer at hvert hold kun kan spille én kamp i hver runde.
    public boolean oneTeamAlreadyPlaying(Match m1, ArrayList<Match> roundMatches) {
        boolean alreadyPlaying = false;
        for (Match m2 : roundMatches) {
            if (m1.getHomeTeam().equals(m2.getHomeTeam())) {
                alreadyPlaying = true;
            }
            if (m1.getHomeTeam().equals(m2.getAwayTeam())) {
                alreadyPlaying = true;
            }
            if (m1.getAwayTeam().equals(m2.getHomeTeam())) {
                alreadyPlaying = true;
            }
            if (m1.getAwayTeam().equals(m2.getAwayTeam())) {
                alreadyPlaying = true;
            }
        }
        return alreadyPlaying;
    }

    //Finder antallet af runder for den valgte division.
    public int getNumRounds(int division) {
        int numRounds = 0;

        //Først tilføjes alle kampe i den valgte division til en samling.
        ArrayList<Match> divMatches = new ArrayList<>();
        for (int i = 0; i < tournamentMatches.size(); i++) {
            if (tournamentMatches.get(i).getHomeTeam().getDivision() == division) {
                divMatches.add(tournamentMatches.get(i));
            }
        }

        int match1Round = divMatches.get(0).getTournamentRound();
        for (int i = 0; i < divMatches.size(); i++) {
            if (i != divMatches.size() - 1) {
                int match2Round = divMatches.get(i + 1).getTournamentRound();
                if (match1Round <= match2Round) {
                    match1Round = match2Round;
                    numRounds = match1Round;
                }
            }
        }
        return numRounds;
    }

    public ArrayList<Match> getTournamentMatches() {
        return tournamentMatches;
    }

    public void addEvent(int id, String type, int moment, int playerid, int matchid) {
        EventMapper.getInstance().createEvent(id, type, moment, playerid, matchid);

    }

    public int getCount() {
        int count = EventMapper.getInstance().getCount();
        return count;
    }

    public ArrayList<Match> getMatches(int division, int round) {
        return MatchMapper.getInstance().getMatches(division, round);
    }

    public ArrayList<Event> getEvents(Match match) {
        return EventMapper.getInstance().getEvents(match);
    }
    
    public void endMatch(Match match){
        match.calculateResult();
    }
    
    public ArrayList<Club> getClubs(int division){
        return ClubMapper.getInstance().getClubs(division);
    }

}
